
#include <stdint.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>

#include "./SystemView/SEGGER_RTT.h"
#include "log2_config.h"

// #define LOG2_CTRL_CLOSE							"0m"										//关闭所有属性
// #define LOG2_CTRL_HIGHLIGHT						"1m"										//设置高亮
// #define LOG2_CTRL_UNDERLINE						"4m"										//下划线 强调
// #define LOG2_CTRL_BLANK							"5m"										//闪烁
// #define LOG2_CTRL_COUNTERVAIL					"7m"										//反显

// #define LOG2_CTRL_TEXT_BLACK           "[2;30m"
// #define LOG2_CTRL_TEXT_RED             "[2;31m"
// #define LOG2_CTRL_TEXT_GREEN           "[2;32m"
// #define LOG2_CTRL_TEXT_YELLOW          "[2;33m"
// #define LOG2_CTRL_TEXT_BLUE            "[2;34m"
// #define LOG2_CTRL_TEXT_MAGENTA         "[2;35m"
// #define LOG2_CTRL_TEXT_CYAN            "[2;36m"
// #define LOG2_CTRL_TEXT_WHITE           "[2;37m"

// #define LOG2_CTRL_TEXT_BRIGHT_BLACK    "[1;30m"
// #define LOG2_CTRL_TEXT_BRIGHT_RED      "[1;31m"
// #define LOG2_CTRL_TEXT_BRIGHT_GREEN    "[1;32m"
// #define LOG2_CTRL_TEXT_BRIGHT_YELLOW   "[1;33m"
// #define LOG2_CTRL_TEXT_BRIGHT_BLUE     "[1;34m"
// #define LOG2_CTRL_TEXT_BRIGHT_MAGENTA  "[1;35m"
// #define LOG2_CTRL_TEXT_BRIGHT_CYAN     "[1;36m"
// #define LOG2_CTRL_TEXT_BRIGHT_WHITE    "[1;37m"

// #define LOG2_CTRL_BG_BLACK             "[24;40m"
// #define LOG2_CTRL_BG_RED               "[24;41m"
// #define LOG2_CTRL_BG_GREEN             "[24;42m"
// #define LOG2_CTRL_BG_YELLOW            "[24;43m"
// #define LOG2_CTRL_BG_BLUE              "[24;44m"
// #define LOG2_CTRL_BG_MAGENTA           "[24;45m"
// #define LOG2_CTRL_BG_CYAN              "[24;46m"
// #define LOG2_CTRL_BG_WHITE             "[24;47m"

// #define LOG2_CTRL_BG_BRIGHT_BLACK      "[4;40m"
// #define LOG2_CTRL_BG_BRIGHT_RED        "[4;41m"
// #define LOG2_CTRL_BG_BRIGHT_GREEN      "[4;42m"
// #define LOG2_CTRL_BG_BRIGHT_YELLOW     "[4;43m"
// #define LOG2_CTRL_BG_BRIGHT_BLUE       "[4;44m"
// #define LOG2_CTRL_BG_BRIGHT_MAGENTA    "[4;45m"
// #define LOG2_CTRL_BG_BRIGHT_CYAN       "[4;46m"
// #define LOG2_CTRL_BG_BRIGHT_WHITE      "[4;47m"


int SEGGER_RTT_vprintf(unsigned BufferIndex, const char * sFormat, va_list * pParamList);


static uint8_t log_level = LOG2_LEVEL_NONE;

#if LOG2_TIME_EN

#include "FreeRTOS.h"
#include "task.h"

TickType_t xTaskGetTickCount( void );

unsigned int log_get_time(void){
	return xTaskGetTickCount();
}


#endif

void log_write(const void* buf, int len){
   (void) SEGGER_RTT_Write(0, buf, len);
}

void log_write_s(const char* str){
  if(str){
    (void) SEGGER_RTT_WriteString(0, str);
  }
}

static inline void log_vprintf(const char * fmt, va_list * pvlist){
  (void)SEGGER_RTT_vprintf(0, fmt, pvlist);
}

void log_printf(const char * fmt, ...){
  va_list vlist;

  va_start(vlist, fmt);
  log_vprintf(fmt, &vlist);
  va_end(vlist);
}

// void log_control(uint8_t ctrl){
//   log_write_s(log_get_ctrl_str(ctrl));
// }

void log_reset_level(void){
  log_level = LOG2_LEVEL_NONE;
}

static inline const char* log_get_level_color(uint8_t level){
  static const char* level_colors[] = {
    NULL,
    LOG2_LEVEL_COLOR_ERR,
    LOG2_LEVEL_COLOR_WRN,
    LOG2_LEVEL_COLOR_INF,
    LOG2_LEVEL_COLOR_DBG,
  };
  return level_colors[level];
}

void log_set_level(uint8_t level){
  if(level != log_level){
    log_level = level;
    log_write_s(log_get_level_color(level));
  }  
}

static void log_write_file(const char* file){
  size_t len = strlen(file);  
  const char* s = file + len;
  while(s > file){
    --s;
    if(*s == '\\' || *s == '/'){
      ++s;
      break;
    }
  }
  log_write_s(s);
}

void log_time(void){
#if LOG2_TIME_EN
  log_printf("%u ", log_get_time());
#endif
}

static void log_print_head(uint8_t level, const char* file, int line, const char* func){
  uint8_t flag = 0;

  log_set_level(level);
  log_time();
  if(file){
    log_write_file(file);
    flag = 1;
  }
  if(line > 0){
    log_printf("(%u)", line);
    flag = 1;
  }
  if(func){
    log_printf(" %s", func);
    flag = 1;
  }
  if(flag != 0){
    log_write(": ", 2);
  }
}

// void log_write_str(uint8_t level, const char* file, int line, const char* func, const char* str){
//   log_print_head(level, file, line, func);
//   log_write_s(str);
// }

void log_print_log(uint8_t level, const char* file, int line, const char* func, const char* fmt, ...){
  log_print_head(level, file, line, func);
  va_list vlist;

  va_start(vlist, fmt);
  log_vprintf(fmt, &vlist);
  va_end(vlist);
  log_write("\r\n", 2);
}

void log_dump_hex(const void* buf, int len, int align){
  const uint8_t* p = buf;
  const uint8_t* pend = p + len;

  if(align < 1){
     align = 16;
  }

  int line_count = 0;
  while(p < pend){
    log_printf(" %02X", *p);
    p++;
    line_count++;
    if(line_count >= align){
      line_count = 0;
      log_write("\r\n", 2);
    }   
  }
  if(line_count > 0){
    log_write("\r\n", 2);
  }
  
}

void log_print_buf(uint8_t level, const char* file, int line, const char* func, const char* tag, const void* buf, int len){

  log_print_head(level, file, line, func);
  if(tag){
    log_printf("%s(%d)\r\n", tag, len);
  }
  else{
    log_printf("(%d)\r\n", len);
  }

  log_dump_hex(buf, len, 16);
}

void log_init(void){
  
}
